﻿using System;

namespace Teal.Compiler {

    /// <summary>
    /// 管理位值的压缩数组，该值表示为布尔值，其中 true 表示位是打开的 (1)，false 表示位是关闭的 (0)。该数组可以根据实际情况动态更改大小。
    /// </summary>
    public sealed class BitArrayList {

        int[] _data;

        int _length;

        /// <summary>
        /// 初始化 <see cref="BitArrayList" /> 类的新实例，该实例可拥有指定数目的位值，位值最初设置为 false。
        /// </summary>
        /// <param name="length">新 <see cref="BitArrayList" /> 中位值的数目。</param>
        public BitArrayList(int capacity = 64) {
            _data = new int[(capacity - 1) / 32 + 1];
        }

        /// <summary>
        /// 初始化 <see cref="BitArrayList" /> 类的新实例，该实例包括从指定的 32 位整数数组复制的位值。
        /// </summary>
        /// <param name="values">包含要复制的值的整数数组，其中每个整数表示 32 个连续位。</param>
        public BitArrayList(int[] data, int length) {
            _data = new int[data.Length];
            Array.Copy(data, _data, _data.Length);
            _length = length;
        }

        /// <summary>
        /// 更改当前列表长度的内部函数。
        /// </summary>
        /// <param name="length"></param>
        void resizeTo(int length) {
            _length = length;

            // 获取数组的实际长度。
            length = (length - 1) / 32 + 1;

            if (_data.Length < length) {
                int[] newData = new int[length];
                Array.Copy(_data, newData, _data.Length);
                _data = newData;
            }

        }

        /// <summary>
        /// 获取或设置 <see cref="T:BitArrayList" /> 中元素的数目。
        /// </summary>
        /// <returns>
        /// <see cref="T:BitArrayList" /> 中元素的数目。</returns>
        public int length {
            get {
                return _length;
            }
            set {
                if (value > _length) {
                    resizeTo(value);
                } else {
                    _length = value;
                }
            }
        }

        /// <summary>
        /// 获取或设置 <see cref="BitArrayList" /> 中特定位置的位的值。
        /// </summary>
        /// <returns>在 <paramref name="index" /> 位置处的位的值。</returns>
        /// <param name="index">要获取或设置的值的从零开始的索引。</param>
        public bool this[int index] {
            get {
                // 超出部分不处理。
                if (index >= _length) {
                    return false;
                }
                return (_data[index / 32] & (1 << (index % 32))) != 0;
            }
            set {

                // 动态更改长度。
                if (index >= _length) {
                    resizeTo(index + 1);
                }

                if (value) {
                    _data[index / 32] |= 1 << (index % 32);
                } else {
                    _data[index / 32] &= ~(1 << (index % 32));
                }

            }
        }

        /// <summary>
        /// 创建 <see cref="BitArrayList" /> 的浅表副本。
        /// </summary>
        /// <returns>
        /// <see cref="BitArrayList" /> 的浅表副本。</returns>
        public BitArrayList clone() {
            return new BitArrayList(_data, _length);
        }

        /// <summary>
        /// 对当前 <see cref="BitArrayList" /> 中的元素和指定的 <see cref="BitArrayList" /> 中的相应元素执行按位“或”运算。
        /// </summary>
        /// <returns>
        /// <see cref="BitArrayList" />，包含对当前 <see cref="BitArrayList" /> 中的元素和指定的 <see cref="BitArrayList" /> 中的相应元素执行按位“或”运算的结果。</returns>
        /// <param name="value">要对其执行按位“或”运算的 <see cref="BitArrayList" />。</param>
        public void or(BitArrayList value) {

            // 更新后自动扩大到最大值。
            if (_length < value._length) {
                _length = value._length;
                for (int i = 0; i < value._data.Length; i++) {
                    _data[i] |= value._data[i];
                }
            } else {
                for (int i = 0; i < _data.Length; i++) {
                    _data[i] |= value._data[i];
                }
            }
        }

        /// <summary>
        /// 对当前 <see cref="BitArrayList" /> 中的元素和指定的 <see cref="BitArrayList" /> 中的相应元素执行按位 AND 运算。
        /// </summary>
        /// <returns>
        /// <see cref="BitArrayList" />，包含对当前 <see cref="BitArrayList" /> 中的元素和指定的 <see cref="BitArrayList" /> 中的相应元素进行按位 AND 运算的结果。</returns>
        /// <param name="value">要对其执行按位 AND 运算的 <see cref="BitArrayList" />。</param>
        public void and(BitArrayList value) {

            // 更新后自动缩小到最小值。
            if (_length > value._length) {
                _length = value._length;
                for (int i = 0; i < value._data.Length; i++) {
                    _data[i] &= value._data[i];
                }
            } else {
                for (int i = 0; i < _data.Length; i++) {
                    _data[i] &= value._data[i];
                }
            }

        }

        /// <summary>
        /// 将 <see cref="BitArrayList" /> 中的所有位设置为指定值。
        /// </summary>
        /// <param name="value">要分配给所有位的布尔值。</param>
        public void setAll(bool value) {
            int num = value ? -1 : 0;
            for (int i = 0; i < _data.Length; i++) {
                _data[i] = num;
            }
        }

        public void setTrue(int length) {
            this.length = length;
            Buffer.SetByte(_data, 0, unchecked((byte)-1));
        }

        public void setFalse(int length) {
            this.length = length;
            Buffer.SetByte(_data, 0, 0);
        }

        /// <summary>
        /// 将 <see cref="BitArrayList" /> 中的指定区域设置为指定值。
        /// </summary>
        /// <param name="value">要分配给所有位的布尔值。</param>
        public void setRange(int offset, int length, bool value) {
            for (int i = offset; i < length; i++) {
                this[i] = value;
            }
        }

        /// <summary>
        /// 返回表示当前对象的字符串。
        /// </summary>
        /// <returns>
        /// 表示当前对象的字符串。
        /// </returns>
        public override string ToString() {
            char[] values = new char[_length];
            for (int i = 0; i < _length; i++) {
                values[i] = this[i] ? '1' : '0';
            }
            return new String(values);
        }
    }

}